/*
 * @Author: liuhandong
 * @Date: 2020-9-24 00:11:48
 */
using UnityEngine;
using System;
using System.Collections.Generic;
using UnityEngine.XR.ARSubsystems;
using UnityEngine.XR.ARFoundation;
#if UNITY_IOS
using UnityEngine.XR.ARKit;
#endif

public class FaceBlendARKitProvider : IFaceBlendProvider
{
    public event System.Action onTrackingStateChange;
#if UNITY_IOS
    private ARKitFaceSubsystem m_ARKitFaceSubsystem;

    private Dictionary<ARKitBlendShapeLocation, ARFaceBlend.Coeffect> mEnumMap = new Dictionary<ARKitBlendShapeLocation, ARFaceBlend.Coeffect>();

    public FaceBlendARKitProvider(ARFace face)
    {
        m_Face = face;
        ARManager.Instance.onRunningStateChanges += _OnSystemStateChanged;
        _CacheFaceSubsystem();
    }
#endif
    private ARFace m_Face;

    private void _CreateFeatureBlendMapping()
    {
#if UNITY_IOS
        mEnumMap[ARKitBlendShapeLocation.BrowDownLeft        ]   = ARFaceBlend.Coeffect.BrowDownLeft;
        mEnumMap[ARKitBlendShapeLocation.BrowDownRight       ]   = ARFaceBlend.Coeffect.BrowDownRight       ;
        mEnumMap[ARKitBlendShapeLocation.BrowInnerUp         ]   = ARFaceBlend.Coeffect.BrowInnerUp         ;
        mEnumMap[ARKitBlendShapeLocation.BrowOuterUpLeft     ]   = ARFaceBlend.Coeffect.BrowOuterUpLeft     ;
        mEnumMap[ARKitBlendShapeLocation.BrowOuterUpRight    ]   = ARFaceBlend.Coeffect.BrowOuterUpRight    ;
        mEnumMap[ARKitBlendShapeLocation.CheekPuff           ]   = ARFaceBlend.Coeffect.CheekPuff           ;
        mEnumMap[ARKitBlendShapeLocation.CheekSquintLeft     ]   = ARFaceBlend.Coeffect.CheekSquintLeft     ;
        mEnumMap[ARKitBlendShapeLocation.CheekSquintRight    ]   = ARFaceBlend.Coeffect.CheekSquintRight    ;
        mEnumMap[ARKitBlendShapeLocation.EyeBlinkLeft        ]   = ARFaceBlend.Coeffect.EyeBlinkLeft        ;
        mEnumMap[ARKitBlendShapeLocation.EyeBlinkRight       ]   = ARFaceBlend.Coeffect.EyeBlinkRight       ;
        mEnumMap[ARKitBlendShapeLocation.EyeLookDownLeft     ]   = ARFaceBlend.Coeffect.EyeLookDownLeft     ;
        mEnumMap[ARKitBlendShapeLocation.EyeLookDownRight    ]   = ARFaceBlend.Coeffect.EyeLookDownRight    ;
        mEnumMap[ARKitBlendShapeLocation.EyeLookInLeft       ]   = ARFaceBlend.Coeffect.EyeLookInLeft       ;
        mEnumMap[ARKitBlendShapeLocation.EyeLookInRight      ]   = ARFaceBlend.Coeffect.EyeLookInRight      ;
        mEnumMap[ARKitBlendShapeLocation.EyeLookOutLeft      ]   = ARFaceBlend.Coeffect.EyeLookOutLeft      ;
        mEnumMap[ARKitBlendShapeLocation.EyeLookOutRight     ]   = ARFaceBlend.Coeffect.EyeLookOutRight     ;
        mEnumMap[ARKitBlendShapeLocation.EyeLookUpLeft       ]   = ARFaceBlend.Coeffect.EyeLookUpLeft       ;
        mEnumMap[ARKitBlendShapeLocation.EyeLookUpRight      ]   = ARFaceBlend.Coeffect.EyeLookUpRight      ;
        mEnumMap[ARKitBlendShapeLocation.EyeSquintLeft       ]   = ARFaceBlend.Coeffect.EyeSquintLeft       ;
        mEnumMap[ARKitBlendShapeLocation.EyeSquintRight      ]   = ARFaceBlend.Coeffect.EyeSquintRight      ;
        mEnumMap[ARKitBlendShapeLocation.EyeWideLeft         ]   = ARFaceBlend.Coeffect.EyeWideLeft         ;
        mEnumMap[ARKitBlendShapeLocation.EyeWideRight        ]   = ARFaceBlend.Coeffect.EyeWideRight        ;
        mEnumMap[ARKitBlendShapeLocation.JawForward          ]   = ARFaceBlend.Coeffect.JawForward          ;
        mEnumMap[ARKitBlendShapeLocation.JawLeft             ]   = ARFaceBlend.Coeffect.JawLeft             ;
        mEnumMap[ARKitBlendShapeLocation.JawOpen             ]   = ARFaceBlend.Coeffect.JawOpen             ;
        mEnumMap[ARKitBlendShapeLocation.JawRight            ]   = ARFaceBlend.Coeffect.JawRight            ;
        mEnumMap[ARKitBlendShapeLocation.MouthClose          ]   = ARFaceBlend.Coeffect.MouthClose          ;
        mEnumMap[ARKitBlendShapeLocation.MouthDimpleLeft     ]   = ARFaceBlend.Coeffect.MouthDimpleLeft     ;
        mEnumMap[ARKitBlendShapeLocation.MouthDimpleRight    ]   = ARFaceBlend.Coeffect.MouthDimpleRight    ;
        mEnumMap[ARKitBlendShapeLocation.MouthFrownLeft      ]   = ARFaceBlend.Coeffect.MouthFrownLeft      ;
        mEnumMap[ARKitBlendShapeLocation.MouthFrownRight     ]   = ARFaceBlend.Coeffect.MouthFrownRight     ;
        mEnumMap[ARKitBlendShapeLocation.MouthFunnel         ]   = ARFaceBlend.Coeffect.MouthFunnel         ;
        mEnumMap[ARKitBlendShapeLocation.MouthLeft           ]   = ARFaceBlend.Coeffect.MouthLeft           ;
        mEnumMap[ARKitBlendShapeLocation.MouthLowerDownLeft  ]   = ARFaceBlend.Coeffect.MouthLowerDownLeft  ;
        mEnumMap[ARKitBlendShapeLocation.MouthLowerDownRight ]   = ARFaceBlend.Coeffect.MouthLowerDownRight ;
        mEnumMap[ARKitBlendShapeLocation.MouthPressLeft      ]   = ARFaceBlend.Coeffect.MouthPressLeft      ;
        mEnumMap[ARKitBlendShapeLocation.MouthPressRight     ]   = ARFaceBlend.Coeffect.MouthPressRight     ;
        mEnumMap[ARKitBlendShapeLocation.MouthPucker         ]   = ARFaceBlend.Coeffect.MouthPucker         ;
        mEnumMap[ARKitBlendShapeLocation.MouthRight          ]   = ARFaceBlend.Coeffect.MouthRight          ;
        mEnumMap[ARKitBlendShapeLocation.MouthRollLower      ]   = ARFaceBlend.Coeffect.MouthRollLower      ;
        mEnumMap[ARKitBlendShapeLocation.MouthRollUpper      ]   = ARFaceBlend.Coeffect.MouthRollUpper      ;
        mEnumMap[ARKitBlendShapeLocation.MouthShrugLower     ]   = ARFaceBlend.Coeffect.MouthShrugLower     ;
        mEnumMap[ARKitBlendShapeLocation.MouthShrugUpper     ]   = ARFaceBlend.Coeffect.MouthShrugUpper     ;
        mEnumMap[ARKitBlendShapeLocation.MouthSmileLeft      ]   = ARFaceBlend.Coeffect.MouthSmileLeft      ;
        mEnumMap[ARKitBlendShapeLocation.MouthSmileRight     ]   = ARFaceBlend.Coeffect.MouthSmileRight     ;
        mEnumMap[ARKitBlendShapeLocation.MouthStretchLeft    ]   = ARFaceBlend.Coeffect.MouthStretchLeft    ;
        mEnumMap[ARKitBlendShapeLocation.MouthStretchRight   ]   = ARFaceBlend.Coeffect.MouthStretchRight   ;
        mEnumMap[ARKitBlendShapeLocation.MouthUpperUpLeft    ]   = ARFaceBlend.Coeffect.MouthUpperUpLeft    ;
        mEnumMap[ARKitBlendShapeLocation.MouthUpperUpRight   ]   = ARFaceBlend.Coeffect.MouthUpperUpRight   ;
        mEnumMap[ARKitBlendShapeLocation.NoseSneerLeft       ]   = ARFaceBlend.Coeffect.NoseSneerLeft       ;
        mEnumMap[ARKitBlendShapeLocation.NoseSneerRight      ]   = ARFaceBlend.Coeffect.NoseSneerRight      ;
        mEnumMap[ARKitBlendShapeLocation.TongueOut           ]   = ARFaceBlend.Coeffect.TongueOut           ;
#endif
    }

    void IFaceBlendProvider.FillCoeffects(Dictionary<ARFaceBlend.Coeffect, float> container)
    {
#if UNITY_IOS
        using (var blendShapes = m_ARKitFaceSubsystem.GetBlendShapeCoefficients(m_Face.trackableId, Unity.Collections.Allocator.Temp))
        {
            foreach (var featureCoefficient in blendShapes)
            {
                if(mEnumMap.ContainsKey(featureCoefficient.blendShapeLocation))
                {
                    container[mEnumMap[featureCoefficient.blendShapeLocation]] = featureCoefficient.coefficient;
                }
            }
        }
#endif
    }

    bool IFaceBlendProvider.IsTracking()
    {
#if UNITY_IOS
        return m_ARKitFaceSubsystem != null && 
        (m_Face.trackingState == TrackingState.Tracking) &&
                (ARManager.Instance.runningState == ARManager.State.Open);
#else
        return false;
#endif
    }

    void IDisposable.Dispose()
    {
        ARManager.Instance.onRunningStateChanges -= _OnSystemStateChanged;
    }

    void _OnSystemStateChanged()
    {
        onTrackingStateChange?.Invoke();
        _CacheFaceSubsystem();
    }

    void _CacheFaceSubsystem()
    {
    #if UNITY_IOS
        if(m_ARKitFaceSubsystem == null && ARManager.Instance.runningState == ARManager.State.Open) 
        {
            var faceManager = ARManager.Instance.GetMainScene().GetFaceManager();
            if (faceManager != null)
            {
                m_ARKitFaceSubsystem = (ARKitFaceSubsystem)faceManager.subsystem;
            }
        }
    #endif
    }
}